package com.heima.stroke.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.heima.commons.domin.bo.RoutePlanResultBO;
import com.heima.commons.domin.bo.TextValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

@Component
public class BaiduMapClient {
    private final static Logger logger = LoggerFactory.getLogger(BaiduMapClient.class);
    @Value("${baidu.map.api}")
    private String api;
    @Value("${baidu.map.ak}")
    private String ak;

    /**
     * 路径规划，计算两点间的距离和预估抵达时长
     *
     * @param origins      起点坐标(经度,纬度)
     * @param destinations 终点坐标(经度,纬度)
     * @return RoutePlanResultBO 路径规划结果
     */
    //TODO：任务3.2-调百度路径计算两点间的距离，和预估抵达时间
    public RoutePlanResultBO pathPlanning(String origins, String destinations) {//起点，终点
        try {
            // 构建参数
            Map<String, String> params = new HashMap<>();//// 创建一个HashMap来存储接口需要的参数
            params.put("origins", origins);//往参数里添加起点坐标（方法接收的第一个参数）
            params.put("destinations", destinations);//往参数里添加终点坐标（方法接收的第二个参数）
            params.put("ak", ak);//往参数里添加百度地图API的访问密钥（ak是已经定义好的变量）

            // 构建完整URL
            String fullUrl = api + "?";// 构建接口的完整URL，先拼接上基础地址和问号（问号是URL参数的开始标志）
            logger.info("调用百度地图路径规划接口，URL: {}", fullUrl);// 打印日志，记录一下要调用的接口地址
            // 使用当前实例而不是手动创建新实例
            String result = this.requestGetAK(fullUrl, params);//// 调用当前类中的requestGetAK方法，传入URL和参数，获取接口返回的结果//这里的this指的是当前对象本身
            // 解析返回结果
            return parseRoutePlanResult(result);// 调用解析方法，把接口返回的字符串结果转换成我们需要的对象格式
        } catch (Exception e) {//// 如果上面的代码执行出错，就会走到这里//// 打印错误日志，包括出错的起点、终点和错误详情
            logger.error("调用百度地图路径规划接口异常，origins:{}，destinations:{}", origins, destinations, e);
            throw new RuntimeException("调用百度地图路径规划接口异常", e);//// 抛出一个运行时异常，告诉调用这个方法的地方出错了
        }
    }

    /**
     * 解析路径规划结果
     *
     * @param result JSON格式的响应结果
     * @return RoutePlanResultBO
     */
    private RoutePlanResultBO parseRoutePlanResult(String result) {// 定义一个私有方法，接收JSON字符串，返回解析后的路径规划结果对象
        JSONObject jsonObject = JSON.parseObject(result);//// 把接口返回的JSON字符串转换成JSON对象（方便我们提取数据）

        // 检查状态码
        int status = jsonObject.getIntValue("status");// 从JSON对象中获取"status"字段的值（状态码）
        if (status != 0) {// 百度地图API规定：status=0表示调用成功，其他值都是失败
            System.out.println("百度地图路径规划接口调用失败，状态码: " + status);//// 如果调用失败，打印错误信息，并返回null表示解析失败
            return null;
        }

        // 获取结果数组中的第一个元素
        JSONArray resultArray = jsonObject.getJSONArray("result");// 从JSON对象中获取"result"数组（这是存放路径信息的主要数据）
        if (resultArray == null || resultArray.isEmpty()) {// 检查这个数组是否为空（比如没有找到路线）
            System.out.println("百度地图路径规划接口返回结果为空");// 如果数组为空，打印提示信息，返回null
            return null;
        }

        JSONObject resultObject = resultArray.getJSONObject(0);// 从结果数组中获取第一个JSON对象（通常路径规划结果会放在第一个位置）

        // 提取distance和duration信息
        JSONObject distanceJson = resultObject.getJSONObject("distance");// 从第一个结果对象中，提取"distance"（距离）和"duration"（时长）这两个JSON对象
        JSONObject durationJson = resultObject.getJSONObject("duration");

        //创建距离信息对象（TextValue）
        TextValue distance = new TextValue(
                distanceJson.getString("text"),//从distanceJson中获取"text"（比如"5.2公里"这种人类易读的文字）
                distanceJson.getIntValue("value")//和"value"（比如5200这种实际数值，单位通常是米）
        );

        TextValue duration = new TextValue(// 同理，创建时长信息对象
                durationJson.getString("text"),// 从durationJson中获取"text"（比如"15分钟"）
                durationJson.getIntValue("value")// 和"value"（比如900这种实际数值，单位通常是秒）
        );

        // 创建并返回RoutePlanResultBO对象
        return new RoutePlanResultBO(duration,distance);// 把距离和时长信息打包到我们自定义的RoutePlanResultBO对象中并返回
    }

    /**
     * 默认ak
     * 选择了ak，使用IP白名单校验：
     * 根据您选择的AK已为您生成调用代码
     * 检测到您当前的ak设置了IP白名单校验
     * 您的IP白名单中的IP非公网IP，请设置为公网IP，否则将请求失败
     * 请在IP地址为xxxxxxx的计算发起请求，否则将请求失败
     */
    /**
     * 使用AK进行GET请求
     * 优化点：
     * 1. 使用try-with-resources确保资源正确关闭
     * 2. 使用StringBuilder替代StringBuffer（单线程环境下更高效）
     * 3. 改进参数拼接逻辑，避免潜在的编码问题
     * 4. 添加超时设置，防止请求无限等待
     * 5. 使用slf4j日志替代system.out
     * 6. 添加更详细的异常处理
     */
    public String requestGetAK(String strUrl, Map<String, String> param) throws Exception {
        if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
            return null;
        }

        StringBuffer queryString = new StringBuffer();
        queryString.append(strUrl);
        for (Map.Entry<?, ?> pair : param.entrySet()) {
            queryString.append(pair.getKey() + "=");
            //    第一种方式使用的 jdk 自带的转码方式  第二种方式使用的 spring 的转码方法 两种均可
            //    queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
            queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
        }

        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }

        java.net.URL url = new URL(queryString.toString());
        System.out.println(queryString.toString());
        URLConnection httpConnection = (HttpURLConnection) url.openConnection();
        httpConnection.connect();

        InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
        BufferedReader reader = new BufferedReader(isr);
        StringBuffer buffer = new StringBuffer();
        String line;
        while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }
        reader.close();
        isr.close();
        System.out.println("AK: " + buffer.toString());
        return buffer.toString();
    }



}
